#region

using System.Collections.Concurrent;

#endregion

namespace Vin.Event;

public class VinEventManager
{
    private static ConcurrentDictionary<Type, List<EventHandler<VinEventArgs>>> _eventHandlers = new();
    private static ConcurrentDictionary<Type, List<Func<object?, VinEventArgs, Task>>> _eventHandlersAsync = new();

    public static Action Register<T>(EventHandler<VinEventArgs> handler) where T : VinEventArgs
    {
        var type = typeof(T);
        if (!_eventHandlers.ContainsKey(type))
        {
            _eventHandlers[type] = new List<EventHandler<VinEventArgs>>();
        }

        _eventHandlers[type].Add(handler);

        return () => UnRegister<T>(handler);
    }

    public static Action Register<T>(Func<object?, VinEventArgs, Task> handle) where T : VinEventArgs
    {
        var type = typeof(T);
        if (!_eventHandlersAsync.ContainsKey(type))
        {
            _eventHandlersAsync[type] = new List<Func<object?, VinEventArgs, Task>>();
        }

        _eventHandlersAsync[type].Add(handle);

        return () => UnRegister<T>(handle);
    }

    public static void UnRegister<T>(EventHandler<VinEventArgs> handler) where T : VinEventArgs
    {
        var type = typeof(T);
        if (_eventHandlers.ContainsKey(type) && _eventHandlers[type].Contains(handler))
        {
            _eventHandlers[type].Remove(handler);
        }
    }

    public static void UnRegister<T>(Func<object?, VinEventArgs, Task> handle) where T : VinEventArgs
    {
        var type = typeof(T);
        if (_eventHandlersAsync.ContainsKey(type) && _eventHandlersAsync[type].Contains(handle))
        {
            _eventHandlersAsync[type].Remove(handle);
        }
    }

    public static void Fire<T>(object? sender, T e) where T : VinEventArgs
    {
        var type = typeof(T);
        if (_eventHandlers.ContainsKey(type))
        {
            foreach (var handler in _eventHandlers[type])
            {
                handler(sender, e);
            }
        }

        if (_eventHandlersAsync.ContainsKey(type))
        {
            foreach (var handler in _eventHandlersAsync[type])
            {
                handler(sender, e).GetAwaiter().GetResult();
            }
        }
    }
}